/* indent.c
 *
 * indent a CASL source program
 *
 * gcc -g -DDEBUG indent.c -o indenty
 *   compile to a execute file for test indent();
 * cproto command to create head file
 *   cproto indent.c > indent.h
 *   
 *
 * written by lasereden<lasereden@yeah.net> on March 4, 2002
 */

#include <ctype.h>

#include "indent.h"

#ifdef DEBUG
/* test indent() */
#include <stdio.h>
#include <stdarg.h>
#include <errno.h>

#define _(X) (X)		/* replace locale */

static void
display (char *format, ...)
{
  va_list ap;

  va_start (ap, format);
  vprintf (format, ap);
  va_end (ap);
}

main (int argc, char **argv)
{
  FILE *in, *out;
  char *src, *dest;
  long len;

  /* show help message */
  if (argc == 2
      && (strcmp (argv[1], "--help") == 0 || strcmp (argv[1], "-h") == 0))
    {
      printf ("Usage: indenty [<source file> [<destination file>]]\n");
      printf ("               -c\tshow cproto command to create head file\n");
      printf ("               -d\tshow debug command\n");
      printf ("               -h | --help\n");
      exit (0);
    }
  /* show cproto command to create head file */
  if (argc == 2 && strcmp (argv[1], "-c") == 0)
    {
      puts ("cproto indent.c > indent.h");
      exit (0);
    }
  /* show debug command */
  if (argc == 2 && strcmp (argv[1], "-d") == 0)
    {
      puts ("gcc -g -DDEBUG indent.c -o indenty");
      exit (0);
    }

  /* open source & destination stream */
  if (argc == 1)
    in = stdin;
  else if ((in = fopen (argv[1], "r")) == NULL)
    {
      perror("");
      exit (0);
    }

  if (argc <= 2)
    out = stdout;
  else if ((out = fopen (argv[2], "w")) == NULL)
    {
      perror("");
      exit (0);
    }

  /* file size */
  fseek (in, 0, SEEK_END);
  len = ftell (in);
  fseek (in, 0, SEEK_SET);

  /* load source program & indent */
  if (src = (char *) malloc (sizeof (char) * (len+1)))
    {
      if (dest = (char *) malloc (sizeof (char) * len))
	{
	  fread (src, len, 1, in);
	  src[len]='\0';
	  indent (src, dest);
	  fprintf (out, dest);
	  free (dest);
	}
      else
	perror("");
      free (src);
    }
  else
    perror("");
}
#else
#include "support.h"

void display(char *format,...);
#endif

/* define if not GNU extension */
static int
isblank (char c)
{
  return c == ' ' || c == '\t';
}

/* input a string with the end of '\n' or '\0'
 * return number of blank before '\n' or '\0'
 */
static int
SkipBlank (char *string)
{
  int i;			/* number of blank */

  for (i = 0; string[i] && string[i] != '\n' && isblank (string[i]); i++);
  return i;
}

/* display a line with line number & content */
static void
display_line (int line_no, char *line_head)
{
  display ("%d: ", line_no);
  while (*line_head &&*line_head != '\n' )
    display ("%c", *line_head++);
  display ("\n");
}

/* indent a CASL source program
 * src - source program string
 * dest - destination program string which is indented
 */
void
indent (char *src, char *dest)	/* src-source text, dest-dest text */
{
  int line_no;
  char *line_head;

  for (line_no = 1, line_head = src; *src; line_no++, line_head = src)
    {
      if (isalpha (*src))	/* label */
	{
	  while (*src != '\n' && *src != '\0' && !isblank (*src))
	    *dest++ = toupper (*src++);
	  if (src - line_head > 6)
	    {
	      display (_("Label is more than 6 charaters in line "));
	      display_line (line_no, line_head);
	    }
	}

      src += SkipBlank (src);
      if (isalpha (*src))
	{
	  /* operation handle */
	  *dest++ = '\t';
	  while (*src != '\n' && *src != '\0' && isalpha (*src))
	    *dest++ = toupper (*src++);

	  src += SkipBlank (src);

	  /* operand handle */
	  if (isalpha (*src) || isdigit (*src) || *src == '-' || *src == '#')
	    {
	      *dest++ = '\t';
	      while (*src != '\n' && *src != '\0' && *src != ';')
		if (isblank (*src))
		  src++;
		else
		  *dest++ = toupper (*src++);
	    }
	  else if (*src == '\'')
	    {
	      *dest++ = '\t';
	      *dest++ = *src++;	/* left quota */
	      while (*src != '\n' && *src != '\0' && *src != '\'')
		*dest++ = *src++;
	      *dest++ = *src++;	/* right quota */
	    }

	  while (*src != '\n' && *src != '\0' && isblank (*src))
	    *dest++ = *src++;
	}

      switch (*src)
	{
	case ';':		/* remark */
	  /* remark handle */
	  while (*src != '\n' && *src != '\0')
	    *dest++ = *src++;
	  if (*src == '\n')
	    *dest++ = *src++;
	  break;
	case '\n':		/* line end */
	  /* line handle */
	  *dest++ = *src++;
	  break;
	case '\0':		/* program end */
	  break;
	default:
	  {
	    /* error message */
	    display(_("%sWrong end of instruction "),src);
	    display_line (line_no, line_head);
	    while(*src&&*src!='\n')
	      src++;
	  }
	}
      if (src - line_head > 72)
	{
	  display (_("Sentence is more than 72 charaters in line "));
	  display_line (line_no, line_head);
	}
    }
  *dest = '\0';
}
